import { select, selectAll } from 'd3-selection'
import mitter from '@/mitt'
import { hasChild } from '../utils'
import { graphNodeContainer, renderNewAllElementNodes, updateExistAllElementNodes, deleteSuperNodes, realTimeUpdateNode, nodeHighLight, hiddenNodeHoverBorderPath } from './drawNode'
import { graphExpandNodeIcon, graphNodeChildCount } from './drawExpandIcon'
import { graphNodeTags } from './drawTag'
import { graphNodeMarkers, markHighLight, removeMarkHighlight, deleteIconMark } from './drawMarker'
import { graphNodeImages, imageControlPointMove, imageControlMoveEnd, deleteTopicImage } from './drawImage'
import { graphNodeLinks } from './drawLink'
import { graphNodeComments } from './drawComment'
import { edgeRoughOptions, graphEdgeContainer, graphNewAllElementEdge, updateExistAllElementEdge, deleteSuperEdges } from './drawEdge'
import { graphOutBorderContainer, graphOutborderElements } from './drawOutBorder'
import { graphSummaryContainer, graphSummaryElements } from './drawSummary'
import {
  graphRelationContainer,
  graphRealRealtionPath,
  bacthDrawRealRelationPath,
  renderVirtualRelationPath,
  updateRenderVirtualRelationPath,
  removeRelationNodeHighLight,
  updateRelationElementPos,
  exitDrawRelation,
  dragRelationControlMove,
  drawRelationControlEnd,
  insertTopicRelation,
  drawRelationPathEnd,
  deleteRelationPath,
  updateRelationStyle,
  updateRelationFullStyle
} from './drawRelation'
import { graphLengendContainer, graphLengends } from './drawLengend'

let svg = null
let mindContainer = null
let nodeContainer = null
let intanceRc = null

export function createCanvasContainer (svgEl, rc) {
  svg = svgEl

  mindContainer = svg.select('.map-outter-container')

  intanceRc = rc

  nodeContainer = graphNodeContainer(svg, mindContainer)

  graphEdgeContainer(mindContainer)

  graphOutBorderContainer(mindContainer)

  graphSummaryContainer(mindContainer)

  graphRelationContainer(svgEl, mindContainer)

  graphLengendContainer(svgEl, mindContainer)
}

export const renderNewNodes = renderNewAllElementNodes
export const renderUpdateNodes = updateExistAllElementNodes
export const renderDeleteNodes = deleteSuperNodes
export const renderNewEdges = graphNewAllElementEdge
export const renderUpdateEdges = updateExistAllElementEdge
export const renderDeleteEdges = deleteSuperEdges
export const drawRealRealtionPath = graphRealRealtionPath

export function renderXmindOtherElement (summaryId, relationNodes, skeletonTheme) {
  graphExpandNodeIcon(nodeContainer)
  graphNodeTags(nodeContainer)
  graphNodeImages(nodeContainer)
  graphNodeLinks(nodeContainer)
  graphNodeComments(nodeContainer)
  graphNodeMarkers(nodeContainer, skeletonTheme)
  graphNodeChildCount(nodeContainer)
  graphSummaryElements(summaryId, nodeContainer)
  graphOutborderElements(nodeContainer, skeletonTheme)
  bacthDrawRealRelationPath(relationNodes)
}

/**
 * 重绘节点样式（该样式不会影响画布布局）
 * @param {*} param0
 */
export function updateRedrawNodeStyle ({ filedName, filedValue, id }) {
  const isRough = Boolean(Number(sessionStorage.getItem('isRough')))
  switch (filedName) {
    case 'textColor':
      select(`#${id}`).selectAll('.node-serial-numner p, .for-block').style('color', filedValue)
      select(`#${id}`).selectAll('.xmind-node-topiclink, .xmind-node-link, .xmind-node-comment').selectAll('svg').attr('fill', filedValue)
      break
    case 'strokeColor':
      select(`#${id}`)
        .select('.x-mind-node-block')
        .select(isRough ? 'path:last-child' : '.valid-path')
        .attr('stroke', filedValue)
      break
    case 'lineColor':
      select('.mind-map-edgebox')
        .selectAll('g')
        .filter(d => d.source.data._id === id || (d.target.data._id === id && d.source.data.isRoot && !d.source.style.lineStyle.lineColor))
        .select('path')
        .attr('stroke', filedValue)
        .attr('fill', d => {
          const gradient = typeof d.source.style.lineStyle.lineWidth === 'string'
          if (gradient) return filedValue
          return 'none'
        })
      break
    case 'backgroundColor':
      select(`#${id}`)
        .select('.x-mind-node-block')
        .select(isRough ? 'path:nth-child(2)' : 'path')
        .attr(isRough ? 'stroke' : 'fill', filedValue)
      break
    default:
      break
  }
}

/**
 * 全局节点统一修改背景色或者文字颜色
 * @param {*} root
 * @param {*} filedName
 * @param {*} filedValue
 */
export function gloabupdateColorStyle (root, filedName, filedValue) {
  const id = root._id
  const node = select(`#${id}`)
  if (node.empty()) return
  const isRough = Boolean(Number(sessionStorage.getItem('isRough')))
  if (filedName === 'backgroundColor') {
    node.select('.x-mind-node-block').select(isRough ? 'path:first-child' : 'path')
      .attr(isRough ? 'stroke' : 'fill', filedValue)
  } else if (filedName === 'textColor') {
    node.select('.x-mind-node-text')
      .select('.node-text-description')
      .style('color', filedValue)
  }
  if (hasChild(root)) {
    root.children.forEach(n => {
      gloabupdateColorStyle(n, filedName, filedValue)
    })
  }
}

/**
 * defs 自定义标签属性定义
 */
export function createCustomXMindDEFS () {
  selectAll('#icon-mb-menu-comment, #icon-zhifeiji_line, #icon-link1').selectAll('path').attr('fill', null)
  const DEFS = svg.append('defs')
  // 连线终点处未选择状态箭头绘制
  DEFS.append('marker')
    .attr('id', 'triangle-downstream')
    .attr('viewBox', '0 0 5 5')
    .attr('refX', 3.7)
    .attr('refY', 2.5)
    .attr('markerUnits', 'strokeWidth')
    .attr('markerWidth', 4)
    .attr('markerHeight', 4)
    .attr('orient', 'auto')
    .append('path')
    .attr('d', 'M 0 0 L 5 2.5 L 0 5 z')
  // 连线起点处未选择状态箭头绘制
  DEFS.append('marker')
    .attr('id', 'triangle-downstream-start')
    .attr('viewBox', '0 0 3 3')
    .attr('refX', 1.5)
    .attr('refY', 1.5)
    .attr('markerUnits', 'strokeWidth')
    .attr('markerWidth', 3)
    .attr('markerHeight', 3)
    .attr('orient', 'auto')
    .append('path')
    .attr('d', 'M 3 1.5 A 1.5 1.5 0 1 0 3 1.51 z')
}

/**
 * 画布所有辅助元素绘制
 * @param {*} skeletonTheme
 */
export function drawXmindAuxiliaryElement (skeletonTheme) {
  const isRough = sessionStorage.getItem('isRough') === '1'
  const controllerList = ['top-left', 'top-right', 'bottom-right', 'bottom-left']
  mindContainer.selectAll('.element-drag-controller, .drag-shadow-node, .drag-shadow-edge, .out-border-desc-text').remove()
  mindContainer
    .insert('g', '.mind-map-edgebox')
    .style('display', 'none')
    .attr('class', 'element-drag-controller')
    .on('dblclick', event => event.stopPropagation())
    .on('click', event => event.stopPropagation())
    .on('mousedown', event => event.stopPropagation())
    .selectAll('point')
    .data(controllerList)
    .enter()
    .append('rect')
    .attr('class', d => `${d}-point control-point`)
    .attr('width', 8)
    .attr('height', 8)
    .attr('stroke', 'rgb(41,183,250)')
    .attr('stroke-width', 2)
    .attr('fill', '#fff')
    .each(function () {
      select(this.parentNode)
        .insert('path', 'rect')
        .attr('stroke', 'rgb(41,183,250)')
        .attr('stroke-width', 2)
        .attr('fill', 'transparent')
    })
    // 节点拖动占位符绘制
  mindContainer.append('g')
    .attr('class', 'drag-shadow-node')
    .style('display', 'none')
    .append(function () {
      const path = 'M0 4 A4 4 0 0 1 4 0 L42 0 A4 4 0 0 1 46 4 L46 14 A4 4 0 0 1 42 18 L4 18 A4 4 0 0 1 0 14z'
      const node = intanceRc.path(path, {
        ...skeletonTheme?.nodeRoughOptions,
        fill: 'rgb(4,183,250)',
        stroke: 'rgb(4,183,250)',
        strokeWidth: 1
      })
      return isRough ? node : select('g').append('path').attr('d', path).attr('fill', 'rgb(4,183,250)').node()
    })
  mindContainer.insert('g', '.mind-map-nodebox')
    .attr('class', 'drag-shadow-edge')
    .style('display', 'none')
    .append('path')
    .attr('stroke-width', 2)
    .attr('stroke', 'rgb(4, 183, 250)')
    .attr('fill', 'transparent')
  mindContainer.append('g')
    .attr('class', 'out-border-desc-text')
    .style('display', 'none')
    .on('click', event => event.stopPropagation())
    .append('g')
    .attr('class', 'border-add-btn')
    .on('click', function (event) {
      mitter.emit('add-out-border-desc', { event, _this: this })
    })
    .each(function () {
      select(this.parentNode)
        .append('foreignObject')
        .style('display', 'none')
        .attr('x', 0)
        .attr('y', -12)
        .append('xhtml:div')
        .attr('class', 'out-border-desc-input')
        .attr('contenteditable', true)
    })
    .append('rect')
    .attr('x', 2)
    .attr('y', 2)
    .attr('width', 16)
    .attr('height', 12)
    .attr('fill', '#fff')
    .each(function () {
      select(this.parentNode)
        .append('image')
        .attr('x', 0)
        .attr('y', 0)
        .attr('width', 20)
        .attr('height', 16)
        .attr('xlink:href', '')
    })
  createCustomXMindDEFS()
}

/**
 * 左键拖动绘制全选主题区域
 * @param {*} event
 * @param {*} domainStart
 * @param {*} updateCb
 */
export function drawAllSelectDomain (event, domainStart, updateCb) {
  if (select('.all-select-domain').empty()) {
    svg
      .append('g')
      .attr('class', 'all-select-domain')
      .append('rect')
      .attr('x', Math.min(domainStart.x, event.x))
      .attr('y', Math.min(domainStart.y, event.y))
      .attr('width', Math.abs(event.x - domainStart.x))
      .attr('height', Math.abs(event.y - domainStart.y))
      .attr('stroke', 'rgb(187,233,255)')
      .attr('stroke-width', 2)
      .attr('fill', 'rgba(234,248,255,.22)')
  } else {
    select('.all-select-domain')
      .select('rect')
      .attr('x', Math.min(domainStart.x, event.x))
      .attr('y', Math.min(domainStart.y, event.y))
      .attr('width', Math.abs(event.x - domainStart.x))
      .attr('height', Math.abs(event.y - domainStart.y))
  }
  updateCb(event)
}

function hideElementControlNode () {
  select('.element-drag-controller').style('display', 'none')
}

function getTopicCenterPosition (id) {
  const { width: canvasWidth, height: canvasHeight } = svg.node().getBoundingClientRect()
  const topicRootNode = nodeContainer.select('.x-mind-root-theme').node().getBoundingClientRect()
  const targetTopicNode = nodeContainer.select(`#${id}`).node().getBoundingClientRect()
  const x = topicRootNode.left - targetTopicNode.left
  const y = topicRootNode.top - targetTopicNode.top
  return {
    x: x + canvasWidth / 2 - targetTopicNode.width / 2,
    y: y + canvasHeight / 2 - targetTopicNode.height / 2
  }
}

export {
  edgeRoughOptions,
  nodeHighLight,
  hiddenNodeHoverBorderPath,
  renderVirtualRelationPath,
  updateRenderVirtualRelationPath,
  realTimeUpdateNode,
  markHighLight,
  removeMarkHighlight,
  hideElementControlNode,
  removeRelationNodeHighLight,
  updateRelationElementPos,
  imageControlPointMove,
  getTopicCenterPosition,
  exitDrawRelation,
  dragRelationControlMove,
  drawRelationControlEnd,
  insertTopicRelation,
  drawRelationPathEnd,
  deleteRelationPath,
  deleteIconMark,
  imageControlMoveEnd,
  deleteTopicImage,
  graphLengends,
  updateRelationStyle,
  updateRelationFullStyle
}
